/**
 * <p>文件名:		ClassUtils.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@ctfo.com)
 */

package com.caits.lbs.framework.utils;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.aopalliance.aop.Advice;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.logging.log4j.Logger;
import org.springframework.util.Assert;

import com.caits.lbs.bean.dbmodel.ETBase;
import com.caits.lbs.framework.log.CommonLogFactory;

/**
 * <p>
 * ClassUtils
 * </p>
 * <p>
 * 类帮助，一些对类的操作或支持
 * </p>
 * 
 * @author 周华彬(zhouhuabin@ctfo.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th><th width="100px">动作</th><th
 *          width="100px">修改人</th><th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>周华彬</td>
 *          <td>2008-7-29 下午02:53:52</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */
public class ClassUtils {

	/** 日志记录器 */
	private static Logger log = CommonLogFactory.getLog();
	/**
	 * 构造器
	 */
	public ClassUtils() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * 获得指定类的父类列表，直到父类为空
	 * 
	 * @param clazz
	 *            需要获得父类的类列表
	 * @return 如果输入类为空则返回null，否则返回指定类的父类继承列表
	 */
	public static List<Class<? extends Object>> getAllSuperclasses(
			Class<? extends Object> clazz) {
		if (clazz == null) {
			return null;
		}
		List<Class<? extends Object>> classes = new ArrayList<Class<? extends Object>>();
		Class<? extends Object> superclass = clazz.getSuperclass();
		while (superclass != null) {
			classes.add(superclass);
			superclass = superclass.getSuperclass();
		}
		return classes;
	}

	/**
	 * 获得指定类所有实现了的接口列表
	 * 
	 * @param clazz
	 *            需要获得接口的类
	 * @return 如果输入的类为空则返回接口列表为null，否则返回指定类的实现接口列表
	 */
	public static List<Class<? extends Object>> getAllInterfaces(
			Class<? extends Object> clazz) {
		if (clazz == null) {
			return null;
		}
		List<Class<? extends Object>> list = new ArrayList<Class<? extends Object>>();
		while (clazz != null) {
			Class<? extends Object>[] interfaces = clazz.getInterfaces();
			for (int i = 0; i < interfaces.length; i++) {
				if (list.contains(interfaces[i]) == false) {
					list.add(interfaces[i]);
				}
				List<Class<? extends Object>> superInterfaces = getAllInterfaces(interfaces[i]);
				for (Iterator<Class<? extends Object>> it = superInterfaces
						.iterator(); it.hasNext();) {
					Class<? extends Object> intface = (Class<? extends Object>) it
							.next();
					if (list.contains(intface) == false) {
						list.add(intface);
					}
				}
			}
			clazz = clazz.getSuperclass();
		}
		return list;
	}

	/**
	 * 获得一组对象的类型 
	 * @param objs
	 * @return
	 */
	public static Class<?>[] getAllClass4Array(Object[] objs){
		if(objs == null){
			return null;
		}
		Class<?>[] classes = new Class[objs.length];
		for(int i =0;i < objs.length; i++){
			Object obj = objs[i];
			classes[i] = obj.getClass();
		}
		return classes;
	}
	/**
	 * 获得指定名称、实现某接口的实例
	 * 
	 * @param className
	 *            实现类名
	 * @param interfaceClass
	 *            限制接口名
	 * @return 如果可以得到并且限定于指定实现，那么返回实例，否则为空
	 */
	public static Object impl(String className,
			Class<? extends Object> interfaceClass) {
		if (!StringUtils.isNullOrBlank(className)) {
			try {
				Class<? extends Object> implClass = Class.forName(className);
	
				if (interfaceClass == null
						|| interfaceClass.isAssignableFrom(implClass)) {
					try {
						return implClass.newInstance();
					} catch (InstantiationException e) {
						log.error("实例化类异常,class="+implClass.getCanonicalName(), e);
					} catch (IllegalAccessException e) {
						log.error("实例化类非法访问错误,class="+implClass.getCanonicalName(), e);
					}
	
				} else {
					log.error("传入的接口为空或未实现指定接口,interfaceClass is null.");
				}
			} catch (ClassNotFoundException e) {
				log.error("传入的实现类找不到,class="+className,e);
			}
		} else {
			log.error("传入的实现类为空,implClass is null.");
		}
		return null;
	}

	/**
	 * 判断一个类是否实现某接口，并返回一个实例
	 * 
	 * @param implClass
	 * @param interfaceClass
	 * @return
	 */
	public static Object impl(Class<? extends Object> implClass,
			Class<? extends Object> interfaceClass) {
		if (implClass != null) {
	
			if (interfaceClass == null
					|| interfaceClass.isAssignableFrom(implClass)) {
				try {
					return implClass.newInstance();
				} catch (InstantiationException e) {
					log.error("实例化类异常,class="+implClass.getCanonicalName(), e);
				} catch (IllegalAccessException e) {
					log.error("实例化类非法访问错误,class="+implClass.getCanonicalName(), e);
				}
	
			} else {
				log.error("传入的接口为空,interfaceClass is null.");
			}
	
		} else {
			log.error("传入的实现类为空,implClass is null.");
		}
		return null;
	}

	
	/**
	 * 在默认类路径下查找资源 ,类路径是--classpath下开始查找
	 * @param resource	以"/"开头表示classpath下查找 
	 * @return
	 */
	public static String getResourceFromClassPath(String resource) {
		//必须用绝对定位
		ClassLoader cl = ClassUtils.class.getClassLoader();
		File directory = new File(cl.getResource(resource)
				.getPath());
		log.info("当前ClassUtils.class路径是:"+directory.getAbsolutePath());
		File newPath = null;
		try {
			String tmp_path = URLDecoder.decode(directory.getCanonicalPath(),
					FileUtils.CONST_UTF8_CHARSET);
			newPath = new File(tmp_path);
//			newPath.mkdir();
		} catch (Exception exp) {
			log.error("创建类路径异常,path=" + directory, exp);
		}
		if (newPath != null)
			return newPath.getPath();
		else
			return File.separator;
	}
	/**
	 * 返回默认的类路径
	 * FIXME 
	 * @return
	 */
	public static <T> String getRealClassPathByClass(Class<T> clazz) {
		//必须用绝对定位
		ClassLoader cl = clazz.getClassLoader();
		File directory = new File(cl.getResource(".").getPath());
		return directory.getAbsolutePath();
	}
	/**
	 * TODO
	 * 获取指定类所在的实际类路径. 
	 * @param clazz
	 * @return
	 */
	public static String getRealFilePathByClass(Class<?> clazz) {
		URL path = clazz.getClassLoader().getResource(clazz.getName().substring(
				clazz.getName().lastIndexOf(".") + 1)
				+ ".class");
		if (path == null) {
			String name = clazz.getName().replaceAll("[.]", "/");
			path = clazz.getResource("/" + name + ".class");
		}
		try {
			String tmp_path = URLDecoder.decode(path.getPath(), FileUtils.CONST_UTF8_CHARSET);
			File file = new File(tmp_path);
			for (int i = 0, count = clazz.getName().split("[.]").length; i < count; i++)
				file = file.getParentFile();
			if (file.getName().toUpperCase().endsWith(".JAR!")) {
				file = file.getParentFile();
			}
			return file.getPath();
		} catch (IOException e) {
			log.error("创建类路径异常,name=" + clazz.getName(), e);
		}
		return null;
	}
	/**
	 * 将 map转换为指定类的实例
	 * @param map
	 * @param clazz
	 * @return
	 */
	public static ETBase map2Bean(Map<String, Object> map,
			Class<? extends ETBase> clazz) {
		Assert.notNull(map,"传入的map不能为空");
		try {
			ETBase obj = clazz.newInstance();
			for(String key:map.keySet()){
				try {
					Class<?> type = PropertyUtils.getPropertyType(obj, key);
					if(type==null){
						log.warn("属性类型为空,key="+key);
						continue;
					}
					if(type.equals(String.class)){
						PropertyUtils.setProperty(obj, key,map.get(key));
					}else if(type.equals(Long.class)||type.equals(long.class)){
						PropertyUtils.setProperty(obj, key,Long.parseLong(""+map.get(key)));
					}else if(type.equals(Integer.class)||type.equals(int.class)){
						PropertyUtils.setProperty(obj, key,Integer.parseInt(""+map.get(key)));
					}else{
						log.warn("属性类型不支持,"+key+",type="+type.getCanonicalName());
					}
				} catch (InvocationTargetException e) {
					log.error("设置属性目标错误,"+key+",msg="+e.getLocalizedMessage(),e);
				} catch (NoSuchMethodException e) {
					log.error("设置属性方法不存在错误,"+key+",msg="+e.getLocalizedMessage(),e);
				} catch (IllegalArgumentException e){
					log.error("设置属性非法参数错误,"+key+",msg="+e.getLocalizedMessage(),e);
				}
			}
			return obj;
		} catch (InstantiationException e) {
			log.error("实例化类错误,"+clazz.getCanonicalName()+",msg="+e.getLocalizedMessage(),e);
		} catch (IllegalAccessException e) {
			log.error("实例化类非法访问错误,"+clazz.getCanonicalName()+",msg="+e.getLocalizedMessage(),e);
		}
		return null;
	}

	/**
	 * 将 bean转换为map的实例
	 * @param map
	 * @param clazz
	 * @return
	 */
	public static Map<String, Object> bean2map(ETBase obj) {
		Assert.notNull(obj,"传入的bean不能为空");
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(obj);
			for(PropertyDescriptor pd:pds){
				String key = pd.getName();
				
				try {
					Class<?> type = PropertyUtils.getPropertyType(obj, key);
					if(type==null){
						log.warn("属性类型为空,key="+key);
						continue;
					}
					if(type.equals(String.class)||type.equals(Long.class)||type.equals(long.class)||type.equals(Integer.class)||type.equals(int.class)){
						map.put(key,PropertyUtils.getProperty(obj, key));
					}else{
						log.warn("属性类型不支持,"+key+",type="+type.getCanonicalName());
					}
				} catch (InvocationTargetException e) {
					log.error("获取属性目标错误,"+key+",msg="+e.getLocalizedMessage(),e);
				} catch (NoSuchMethodException e) {
					log.error("获取属性方法不存在错误,"+key+",msg="+e.getLocalizedMessage(),e);
				} catch (IllegalArgumentException e){
					log.error("获取属性非法参数错误,"+key+",msg="+e.getLocalizedMessage(),e);
				}
			}
			return map;
		} catch (IllegalAccessException e) {
			log.error("转换实例到map错误,"+obj.getId()+",msg="+e.getLocalizedMessage(),e);
		}
		return null;
	}
	/**
	 * 
	 * 判断实例是否是一个父类或接口的实例 
	 * @param instance	实例
	 * @param superClazz	要判断的类
	 * @return	
	 */
	public static <T> boolean isInstanceOfClass(Object instance,Class<T> superClazz) {
		return instance!=null&&superClazz!=null&&superClazz.isAssignableFrom(instance.getClass());
	}
	/**
	 * 
	 * 判断一个类是否是另一个类或接口的子孙
	 * @param superClazz	父类
	 * @param childClazz	子类
	 * @return
	 */
	public static <T,K> boolean isChildOfSuperClass(Class<T> superClazz,Class<K> childClazz) {
		return childClazz!=null&&superClazz!=null&&superClazz.isAssignableFrom(childClazz);
	}
	/**
	 * FIXME
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		String path = getResourceFromClassPath("jdbc.properties");
		log.info("获得类的完整路径是:"+path);
		log.info("获取类的getRealClassPathByClass路径:"+getRealClassPathByClass(Advice.class));
		log.info("获取类的getRealFilePathByClass路径:"+getRealFilePathByClass(Advice.class));
		log.info("获取类的getClassFileName路径:"+org.springframework.util.ClassUtils.classPackageAsResourcePath(Advice.class));
		log.info("获取类的isInstanceOfClass实例:"+isInstanceOfClass(new ETBase(), ETBase.class));
	}

}
